package com.witype.timeline.line;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 * Created by WiType on 2017/4/16.
 * Email witype716@gmail.com
 * Desc:
 */

public class TimeLine implements Handler.Callback {

    private static final int MESSAGE_NEXT = 0xF1;
    private static final int MESSAGE_END = 0xF2;

    private static TimeLine INSTANCE = new TimeLine();

    private final List<PlayLine> playLines = Collections.synchronizedList(new ArrayList<PlayLine>());

    private OnAction onAction;

    private Handler handler;

    public static TimeLine get() {
        return INSTANCE;
    }

    private TimeLine() {
        handler = new Handler(Looper.getMainLooper(),this);
    }

    private void setPlayLines(List<PlayLine> playLines) {
        synchronized (this.playLines) {
            Collections.reverse(playLines);
            this.playLines.addAll(playLines);
        }
    }

    public void start(OnAction onAction) {
        this.onAction = onAction;
        if (playLines.size() == 0) {
            onActionNone();
        } else {
            handler.sendEmptyMessage(MESSAGE_NEXT);
        }
    }

    public void start(OnAction onAction,List<PlayLine> playLines) {
        setPlayLines(playLines);
        start(onAction);
    }

    @Override
    public boolean handleMessage(Message message) {
        PlayLine playLine = (PlayLine) message.obj;
        switch (message.what) {
            case MESSAGE_END:
                if (playLine != null) {
                    playLines.remove(playLine);
                    onActionEnd(playLine);
                }
            case MESSAGE_NEXT:
                PlayLine nextLine = getNextLine(playLine);
                if(nextLine == null || playLines.size() == 0) {
                    onActionNone();
                }
                onActionNext(nextLine);
                postPlayLineMessage(nextLine);
                break;
        }
        return false;
    }

    private void postPlayLineMessage(PlayLine nextLine) {
        if (nextLine == null) return;
        int messageWhat;
        long begin = nextLine.getBeginTimestamp();
        long messageDelayedTime = nextLine.getEndTimestamp() - System.currentTimeMillis();
        messageDelayedTime = messageDelayedTime <= 0 ? 0 : messageDelayedTime;
        if (begin > System.currentTimeMillis()) {
            messageWhat = MESSAGE_NEXT;
            messageDelayedTime = nextLine.getBeginTimestamp() - System.currentTimeMillis();
            onActionWait(messageDelayedTime);
        } else if (messageDelayedTime <= nextLine.getEachTimestamp()) {
            messageWhat = MESSAGE_END;
        } else {
            messageDelayedTime = nextLine.getEachTimestamp();
            messageWhat = MESSAGE_NEXT;
        }
        Message message = handler.obtainMessage();
        message.what = messageWhat;
        message.obj = nextLine;
        handler.sendMessageDelayed(message,messageDelayedTime);
    }

    private PlayLine getNextLine(PlayLine playLine) {
        PlayLine earliest = null;
        synchronized (playLines) {
            Iterator<PlayLine> iterator = playLines.iterator();
            while (iterator.hasNext()) {
                PlayLine next = iterator.next();
                if (next != playLine && isLineAvailable(next)) {
                    earliest = next;
                }
            }
            if (isLineAvailable(playLine)) {
                earliest = earliest == null ? playLine : earliest;
            } else if (earliest == null && playLines.size() > 0) {
                earliest = getNextFutureLine();
            }
            return earliest;
        }
    }

    private PlayLine getNextFutureLine() {
        PlayLine earliest = null;
        synchronized (playLines) {
            Iterator<PlayLine> iterator = playLines.iterator();
            while (iterator.hasNext()) {
                PlayLine next = iterator.next();
                if (isLineAvailableForFuture(next)) {
                    earliest = next;
                }
            }
            return earliest;
        }
    }

    private boolean isLineAvailable(PlayLine playLine) {
        return playLine != null &&
                playLine.getEndTimestamp() > System.currentTimeMillis() &&
                playLine.getBeginTimestamp() <= System.currentTimeMillis();
    }

    private boolean isLineAvailableForFuture(PlayLine playLine) {
        return playLine != null &&
                playLine.getBeginTimestamp() > System.currentTimeMillis();
    }

    private void onActionNone() {
        if (onAction != null) onAction.onNone();
    }

    private void onActionNext(PlayLine playLine) {
        if (onAction != null && playLine != null) onAction.onAction(playLine);
    }

    private void onActionEnd(PlayLine playLine) {
        if (onAction != null && playLine != null) onAction.onEnd(playLine);
    }

    private void onActionWait(long time) {
        if (onAction != null) onAction.onWait(time);
    }

    public void release() {
        synchronized (this.playLines) {
            this.playLines.clear();
        }
        handler.removeMessages(MESSAGE_NEXT);
        handler.removeMessages(MESSAGE_END);
    }

    public interface OnAction {

        void onAction(PlayLine playLine);

        void onEnd(PlayLine playLine);

        void onWait(long time);

        void onNone();
    }
}
